package db

import (
	"dc-news/common/global/setting"
	"dc-news/dao/model"
	"dc-news/entity"
	"encoding/json"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"io/ioutil"
	"net/http"
	"time"
)

// GetUserByEmail 通过邮箱获取用户
func GetUserByEmail(email string) (user *entity.User, err error) {
	user = new(entity.User)
	err = DB.
		Model(&entity.User{}).
		Where("email = ?", email).
		First(user).
		Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		} else {
			zap.S().Error("通过邮箱获取用户操作数据库错误: ", err)
			return nil, err
		}
	}
	return
}

// GetUserByUsername 通过用户名获取用户
func GetUserByUsername(username string) (user *entity.User, err error) {
	user = new(entity.User)
	err = DB.
		Model(&entity.User{}).
		Where("username = ?", username).
		First(user).
		Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		} else {
			zap.S().Error("通过用户名获取用户操作数据库错误: ", err)
			return nil, err
		}
	}
	return
}

// ChangePasswordById 通过id修改密码
func ChangePasswordById(id int, password string) (err error) {
	err = DB.
		Model(&entity.User{}).
		Where("id = ?", id).
		Update("password", password).
		Error
	if err != nil {
		zap.S().Error("通过id修改密码操作数据库错误: ", err)
	}
	return err
}

// CreateUser 创建用户
func CreateUser(user *entity.User) error {
	tx := DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	err := tx.Create(user).Error
	if err != nil {
		tx.Rollback()
		return err
	}
	err = tx.
		Model(&entity.UserSetting{}).
		Create(&entity.UserSetting{
			UserId:     user.ID,
			ThemeColor: "yellow",
			FrontSize:  17,
			DarkMode:   1,
			UseMode:    1,
		}).
		Error
	if err != nil {
		tx.Rollback()
		zap.S().Error("创建用户操作数据库错误: ", err)
		return err
	}
	return tx.Commit().Error
}

// CheckUsernameAndEmail 查看是否存在该用户
func CheckUsernameAndEmail(username string, email string) (exist bool) {
	exist = false
	err := DB.Raw("select 1 as exist from users where username = ? or email = ? limit 1", username, email).Scan(&exist)
	if err != nil {
		zap.S().Error("查看是否存在该用户操作数据库错误: ", err)
	}
	return
}

// ConfirmEmailByUserId 确认邮件
func ConfirmEmailByUserId(id int) (err error) {
	err = DB.Model(&entity.User{}).
		Where("id = ?", id).
		Update("email_confirm", 1).
		Error
	if err != nil {
		zap.S().Error("确认邮件操作数据库错误: ", err)
	}
	return
}

// GetUserById 通过id获取用户
func GetUserById(id int) (user *entity.User, err error) {
	user = new(entity.User)
	err = DB.Model(&entity.User{}).Where("id = ?", id).First(user).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		} else {
			zap.S().Error("通过id获取用户操作数据库错误: ", err)
			return nil, err
		}
	}
	return
}

// GetUserSettingById 通过id获取用户设置
func GetUserSettingById(id int) (setting *entity.UserSetting, err error) {
	setting = new(entity.UserSetting)
	err = DB.Model(&entity.UserSetting{}).Where("user_id = ?", id).First(setting).Error
	if err != nil {
		zap.S().Error("通过id获取用户设置操作数据库错误: ", err)
	}
	return
}

// UpdateUserSettingById 通过id更新用户设置
func UpdateUserSettingById(id int, setting *entity.UserSetting) (err error) {
	err = DB.Model(&entity.UserSetting{}).Where("user_id = ?", id).Updates(setting).Error
	if err != nil {
		zap.S().Error("通过id更新用户设置操作数据库错误: ", err)
	}
	return
}

// UpdateUserInfoById 通过id更新用户信息
func UpdateUserInfoById(id int, user *entity.User) (err error) {
	err = DB.Model(&entity.User{}).Where("id = ?", id).Updates(user).Error
	if err != nil {
		zap.S().Error("通过id更新用户信息操作数据库错误: ", err)
	}
	return
}

// GetUserIsMutedById 通过id查询用户是否禁言
func GetUserIsMutedById(id int) (isMuted bool, err error) {
	err = DB.
		Model(&entity.User{}).
		Select("is_muted").
		Where("id = ?", id).
		Find(&isMuted).
		Error
	if err != nil {
		zap.S().Error("通过id查询用户是否禁言操作数据库错误: ", err)
	}
	return
}

func GetUseReportById(id int) (report *model.Report) {
	now := time.Now().Unix()
	fromService := getReportFromService(id, now-2626560)
	commentCount := GetCommentCountById(id, now-2626560)
	commentLikeCount := GetCommentLikeCount(id, now-2626560)
	newsLikeCount := GetNewsLikeById(id, now-2626560)
	report = &model.Report{
		WordCount:        fromService.WordCount,
		NewsLikeCount:    newsLikeCount,
		CommentLikeCount: commentLikeCount,
		CommentCount:     commentCount,
		ChannelCount: struct {
			NewsHot           int `json:"news_hot"`
			NewsSociety       int `json:"news_society"`
			NewsEntertainment int `json:"news_entertainment"`
			NewsTech          int `json:"news_tech"`
			NewsMilitary      int `json:"news_military"`
			NewsSports        int `json:"news_sports"`
			NewsCar           int `json:"news_car"`
			NewsFood          int `json:"news_food"`
		}{
			NewsHot:           fromService.ChannelCount.NewsHot,
			NewsSociety:       fromService.ChannelCount.NewsSociety,
			NewsEntertainment: fromService.ChannelCount.NewsEntertainment,
			NewsTech:          fromService.ChannelCount.NewsTech,
			NewsMilitary:      fromService.ChannelCount.NewsMilitary,
			NewsSports:        fromService.ChannelCount.NewsSports,
			NewsCar:           fromService.ChannelCount.NewsCar,
			NewsFood:          fromService.ChannelCount.NewsFood,
		},
		WordCloud:  fromService.WordCloud,
		DataUpdate: now,
	}
	return report
}

func getReportFromService(id int, after int64) *model.ReportServiceResp {
	report := &model.ReportServiceResp{}
	client := &http.Client{}
	url := fmt.Sprintf("%s/report/%d?after=%d", setting.Conf.ReportServiceDomain, id, after)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		zap.S().Error(err)
	}
	resp, err := client.Do(req)
	if err != nil {
		zap.S().Error(err)
	}
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		zap.S().Error(err)
	}
	_ = json.Unmarshal(bodyText, report)
	return report
}
